import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf

def main1():
    '''
    使用机器学习(sklearn模块)了解线性回归计算方法: w1x1 + w2x2 + wnxn
    线性回归定义: 线性回归(Linear regression)是利用回归方程(函数)
    对一个或多个自变量(特征值)和因变量(目标值)之间关系进行建模的一种分析方式。
    我们来看几个例子

    期末成绩：0.7×考试成绩+0.3×平时成绩    # 0.7和0.3是系数  ->  求和  获取预测值
    房子价格 = 0.02×中心区域的距离 + 0.04×城市一氧化氮浓度 + (-0.12×自住房平均房价) + 0.254×城镇犯罪率
    :return:
    '''
    from sklearn.linear_model import LinearRegression

    # 获取数据
    #平均成绩   当前考试成绩
    x = [[80, 86],
         [82, 80],
         [85, 78],
         [90, 90],
         [86, 82],
         [82, 90],
         [78, 80],
         [92, 94]]
    # 目表预测值
    y = [84.2, 80.6, 80.1, 90, 83.2, 87.6, 79.4, 93.4]

    # 实例化API
    estimator = LinearRegression()
    estimator.fit(x, y)

    # 获取系数
    coefRet = estimator.coef_
    print(f"平均成绩系数: {coefRet[0]}")
    print(f"考试成绩系数: {coefRet[1]}")
    print(f"coef值: {coefRet}")

    # 预测成绩
    ret = estimator.predict([[100, 80]])
    print(f"预测成绩是: {ret}")

def main():
    '''
    使用tf完成房价的线性回归计算
    :return:
    '''
    import numpy as np

    def numpyLine():
        '''
        numpy 下的线性回算法
        :return:
        '''
        a, b = 0, 0
        num_epoch = 10000
        learning_rate = 1e-3
        for e in range(num_epoch):
            # 手动计算损失函数关于自变量（模型参数）的梯度
            y_pred = a * X + b
            grad_a, grad_b = (y_pred - y).dot(X), (y_pred - y).sum()

            # 更新参数
            a, b = a - learning_rate * grad_a, b - learning_rate * grad_b
            print(f"a, b更新后: {a} {b}")
        print(f"最后得导数为: {a} {b}")

    def TfLine(X, y):
        '''
        tf 线性回归求导方法
        :return:
        '''
        import tensorflow as tf

        # 1、定义Tensor类型
        X = tf.constant(X)
        y = tf.constant(y)

        # 2、参数使用变量初始化
        a = tf.Variable(initial_value=0.)
        b = tf.Variable(initial_value=0.)
        variables = [a, b]

        num_epoch = 10000
        optimizer = tf.keras.optimizers.SGD(learning_rate=1e-3)
        for e in range(num_epoch):
            # 使用tf.GradientTape()记录损失函数的梯度信息
            with tf.GradientTape() as tape:
                # 根据导数计算 出预测值
                y_pred = a * X + b
                # 计算损失函数 计算公式  (预测值 - 真实值)^2 平方 求和, 得到损失值
                loss = 0.5 * tf.reduce_sum(tf.square(y_pred - y))

            # TensorFlow自动计算损失函数关于自变量（模型参数）的梯度
            grads = tape.gradient(loss, variables)
            # TensorFlow自动根据梯度更新参数
            optimizer.apply_gradients(grads_and_vars=zip(grads, variables))
            print(f"a, b更新后: a={a.numpy()} b={b.numpy()}")

        print(f"最后得导数为: {a} {b}")
        print(f"最后得导数为: a={a.numpy()} b={b.numpy()}")


    # 获取数据
    X_raw = np.array([2013, 2014, 2015, 2016, 2017], dtype=np.float32)
    y_raw = np.array([12000, 14000, 15000, 16500, 17500], dtype=np.float32)

    # 归一化处理
    X = (X_raw - X_raw.min()) / (X_raw.max() - X_raw.min())
    y = (y_raw - y_raw.min()) / (y_raw.max() - y_raw.min())

    # numpy求导方法
    # numpyLine()

    # TensorFlow 下的线性回归
    TfLine(X, y)






if __name__ == '__main__':
    main()



